//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_chat_api_serv

import (
	"context"
	"math"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/chat_dao"
	"atomgit.com/openlinksaas/api-server/dao/project_dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_chat"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_chat_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

func (apiImpl *ProjectChatApiImpl) CreateGroup(ctx context.Context, req *project_chat_api.CreateGroupRequest) (*project_chat_api.CreateGroupResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_chat_api.CreateGroupResponse{
			Code:   project_chat_api.CreateGroupResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_chat_api.CreateGroupResponse{
			Code:   project_chat_api.CreateGroupResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_chat_api.CreateGroupResponse{
			Code:   project_chat_api.CreateGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	memberUserIdMap := map[string]bool{sessionItem.UserId: true}
	for _, memberUserId := range req.MemberUserIdList {
		memberUserIdMap[memberUserId] = true
	}

	for memberUserId := range memberUserIdMap {
		exist, err := project_dao.MemberInfoDao.Exist(ctx, req.ProjectId, memberUserId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &project_chat_api.CreateGroupResponse{
				Code:   project_chat_api.CreateGroupResponse_CODE_NO_MEMBER,
				ErrMsg: "项目成员不存在",
			}, nil
		}
	}

	chatGroupId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = chat_dao.GroupDao.Insert(sessCtx, &chat_dao.ChatGroupInfoDbItem{
			ChatGroupId: chatGroupId,
			ProjectId:   req.ProjectId,
			Title:       req.Title,
			System:      false,
			OwnerUserId: sessionItem.UserId,
			LastMsgId:   "",
			CreateTime:  nowTime,
		})
		if err != nil {
			return nil, err
		}
		for memberUserId := range memberUserIdMap {
			err = chat_dao.GroupMemberDao.Insert(sessCtx, &chat_dao.MemberDbItem{
				ProjectId:   req.ProjectId,
				ChatGroupId: chatGroupId,
				UserId:      memberUserId,
				UnreadCount: 0,
				LastMsgTime: nowTime,
				JoinTime:    nowTime,
			})
			if err != nil {
				return nil, err
			}
		}
		return &project_chat_api.CreateGroupResponse{
			Code:        project_chat_api.CreateGroupResponse_CODE_OK,
			ChatGroupId: chatGroupId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	for memberUserId := range memberUserIdMap {
		go api_common.SendNoticeToUser(context.Background(), memberUserId, &notices_chat.UpdateGroupMemberNotice{
			ProjectId:   req.ProjectId,
			ChatGroupId: chatGroupId,
		})
	}

	return ret.(*project_chat_api.CreateGroupResponse), nil
}

func (apiImpl *ProjectChatApiImpl) UpdateGroup(ctx context.Context, req *project_chat_api.UpdateGroupRequest) (*project_chat_api.UpdateGroupResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_chat_api.UpdateGroupResponse{
			Code:   project_chat_api.UpdateGroupResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_chat_api.UpdateGroupResponse{
			Code:   project_chat_api.UpdateGroupResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_chat_api.UpdateGroupResponse{
			Code:   project_chat_api.UpdateGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	groupItem, err := chat_dao.GroupDao.Get(ctx, req.ProjectId, req.ChatGroupId)
	if err != nil {
		return &project_chat_api.UpdateGroupResponse{
			Code:   project_chat_api.UpdateGroupResponse_CODE_NO_CHAT_GROUP,
			ErrMsg: "沟通群不存在",
		}, nil
	}
	userPerm := apiImpl.calcUserPerm(groupItem, sessionItem.UserId, projectItem, roleItem)
	if !userPerm.CanUpdate {
		return &project_chat_api.UpdateGroupResponse{
			Code:   project_chat_api.UpdateGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = chat_dao.GroupDao.UpdateTitle(sessCtx, req.ProjectId, req.ChatGroupId, req.Title)
		if err != nil {
			return nil, err
		}
		return &project_chat_api.UpdateGroupResponse{
			Code: project_chat_api.UpdateGroupResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	memberItemList, err := chat_dao.GroupMemberDao.ListMember(ctx, req.ProjectId, req.ChatGroupId)
	if err == nil {
		for _, memberItem := range memberItemList {
			go api_common.SendNoticeToUser(context.Background(), memberItem.UserId, &notices_chat.UpdateGroupNotice{
				ProjectId:   req.ProjectId,
				ChatGroupId: req.ChatGroupId,
			})
		}
	}
	return ret.(*project_chat_api.UpdateGroupResponse), nil
}

func (apiImpl *ProjectChatApiImpl) RemoveGroup(ctx context.Context, req *project_chat_api.RemoveGroupRequest) (*project_chat_api.RemoveGroupResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_chat_api.RemoveGroupResponse{
			Code:   project_chat_api.RemoveGroupResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_chat_api.RemoveGroupResponse{
			Code:   project_chat_api.RemoveGroupResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_chat_api.RemoveGroupResponse{
			Code:   project_chat_api.RemoveGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}

	groupItem, err := chat_dao.GroupDao.Get(ctx, req.ProjectId, req.ChatGroupId)
	if err != nil {
		return &project_chat_api.RemoveGroupResponse{
			Code: project_chat_api.RemoveGroupResponse_CODE_OK,
		}, nil
	}
	userPerm := apiImpl.calcUserPerm(groupItem, sessionItem.UserId, projectItem, roleItem)
	if !userPerm.CanRemove {
		return &project_chat_api.RemoveGroupResponse{
			Code:   project_chat_api.RemoveGroupResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		//只移除项目成员
		err = chat_dao.GroupMemberDao.RemoveByChatGroup(sessCtx, req.ProjectId, req.ChatGroupId)
		if err != nil {
			return nil, err
		}
		return &project_chat_api.RemoveGroupResponse{
			Code: project_chat_api.RemoveGroupResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_chat.LeaveGroupNotice{
		ProjectId:   req.ProjectId,
		ChatGroupId: req.ChatGroupId,
	})
	return ret.(*project_chat_api.RemoveGroupResponse), nil
}

func (apiImpl *ProjectChatApiImpl) GetGroup(ctx context.Context, req *project_chat_api.GetGroupRequest) (*project_chat_api.GetGroupResponse, error) {
	emptyInfo := &project_chat_api.ChatGroupInfo{
		UserPerm: &project_chat_api.UserPerm{},
	}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_chat_api.GetGroupResponse{
			Code:      project_chat_api.GetGroupResponse_CODE_WRONG_SESSION,
			ErrMsg:    "会话不存在",
			ChatGroup: emptyInfo,
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_chat_api.GetGroupResponse{
			Code:      project_chat_api.GetGroupResponse_CODE_NO_PROJECT,
			ErrMsg:    "项目不存在",
			ChatGroup: emptyInfo,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_chat_api.GetGroupResponse{
			Code:      project_chat_api.GetGroupResponse_CODE_NO_PERMISSION,
			ErrMsg:    "没有权限",
			ChatGroup: emptyInfo,
		}, nil
	} else if err != nil {
		return nil, err
	}

	memberItem, _ := chat_dao.GroupMemberDao.Get(ctx, req.ProjectId, req.ChatGroupId, sessionItem.UserId) //skip error check
	unreadCount := uint32(0)
	if memberItem != nil {
		unreadCount = memberItem.UnreadCount
	}
	if !(sessionItem.UserId == projectItem.OwnerUserId || roleItem.BasicInfo.Admin) {
		if memberItem == nil {
			return &project_chat_api.GetGroupResponse{
				Code:      project_chat_api.GetGroupResponse_CODE_NO_PERMISSION,
				ErrMsg:    "没有权限",
				ChatGroup: emptyInfo,
			}, nil
		}
	}
	groupItem, err := chat_dao.GroupDao.Get(ctx, req.ProjectId, req.ChatGroupId)
	if err != nil {
		return &project_chat_api.GetGroupResponse{
			Code:      project_chat_api.GetGroupResponse_CODE_NO_CHAT_GROUP,
			ErrMsg:    "沟通群不存在",
			ChatGroup: emptyInfo,
		}, nil
	}

	userIdList := []string{groupItem.OwnerUserId}

	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}

	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	groupInfo := groupItem.ToChatGroupInfo(apiImpl.calcUserPerm(groupItem, sessionItem.UserId, projectItem, roleItem), unreadCount)

	userItem, ok := userItemMap[groupItem.OwnerUserId]
	if ok {
		groupInfo.OwnerDisplayName = userItem.BasicInfo.DisplayName
		groupInfo.OwnerLogoUri = userItem.BasicInfo.LogoUri
	}
	//调整sortValue
	if projectItem.DefaultChatGroupId == groupInfo.ChatGroupId {
		groupInfo.SortValue = math.MaxInt64
	}

	return &project_chat_api.GetGroupResponse{
		Code:      project_chat_api.GetGroupResponse_CODE_OK,
		ChatGroup: groupInfo,
	}, nil
}

func (apiImpl *ProjectChatApiImpl) ListGroup(ctx context.Context, req *project_chat_api.ListGroupRequest) (*project_chat_api.ListGroupResponse, error) {
	emptyList := []*project_chat_api.ChatGroupInfo{}

	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_chat_api.ListGroupResponse{
			Code:   project_chat_api.ListGroupResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	//检查权限
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_chat_api.ListGroupResponse{
			Code:          project_chat_api.ListGroupResponse_CODE_NO_PROJECT,
			ErrMsg:        "项目不存在",
			ChatGroupList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_chat_api.ListGroupResponse{
			Code:          project_chat_api.ListGroupResponse_CODE_NO_PERMISSION,
			ErrMsg:        "没有权限",
			ChatGroupList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	skipChatGroupId := ""
	if req.SkipSystemGroup {
		skipChatGroupId = projectItem.DefaultChatGroupId
	}

	memberItemList, err := chat_dao.GroupMemberDao.ListChatGroup(ctx, req.ProjectId, sessionItem.UserId, skipChatGroupId)
	if err != nil {
		return nil, err
	}

	groupIdList := []string{}
	for _, memberItem := range memberItemList {
		groupIdList = append(groupIdList, memberItem.ChatGroupId)
	}
	groupItemList, err := chat_dao.GroupDao.ListById(ctx, req.ProjectId, groupIdList)
	if err != nil {
		return nil, err
	}
	groupItemMap := map[string]*chat_dao.ChatGroupInfoDbItem{}
	for _, groupItem := range groupItemList {
		groupItemMap[groupItem.ChatGroupId] = groupItem
	}

	//获取用户信息
	userIdList := []string{}
	for _, groupItem := range groupItemList {
		userIdList = append(userIdList, groupItem.OwnerUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	//生成结果
	groupInfoList := []*project_chat_api.ChatGroupInfo{}
	for _, memberItem := range memberItemList {
		groupItem, ok := groupItemMap[memberItem.ChatGroupId]
		if !ok {
			continue
		}
		groupInfo := groupItem.ToChatGroupInfo(apiImpl.calcUserPerm(groupItem, sessionItem.UserId, projectItem, roleItem), memberItem.UnreadCount)
		userItem, ok := userItemMap[groupItem.OwnerUserId]
		if ok {
			groupInfo.OwnerDisplayName = userItem.BasicInfo.DisplayName
			groupInfo.OwnerLogoUri = userItem.BasicInfo.LogoUri
		}
		//调整sortValue
		if projectItem.DefaultChatGroupId == groupInfo.ChatGroupId {
			groupInfo.SortValue = math.MaxInt64
		}
		groupInfoList = append(groupInfoList, groupInfo)
	}
	return &project_chat_api.ListGroupResponse{
		Code:          project_chat_api.ListGroupResponse_CODE_OK,
		ChatGroupList: groupInfoList,
	}, nil
}
